#include "fxcc/core/graph/directX11/RenderStates.h"

using namespace fxcc::graph::directX11;
using namespace fxcc::graph::common;
using namespace fxcc::graph;


bool fxcc::graph::directX11::RenderStates::Init()
{

	InitVertexDesc();

	InitIndexDesc();

	InitModeDesc();

	InitSamplerDesc();

	InitFormatDesc();

	return true;
};

bool fxcc::graph::directX11::RenderStates::InitFormatDesc()
{
	m_FormatDescs[0] = { DXGI_FORMAT_UNKNOWN,DXGI_FORMAT_UNKNOWN };
	m_FormatDescs[1] = { DXGI_FORMAT_R8_UNORM ,DXGI_FORMAT_R16_FLOAT };
	m_FormatDescs[2] = { DXGI_FORMAT_R8G8_UNORM ,DXGI_FORMAT_R16G16_FLOAT };
	m_FormatDescs[3] = { DXGI_FORMAT_R8G8B8A8_UNORM ,DXGI_FORMAT_R16G16B16A16_FLOAT };
	m_FormatDescs[4] = { DXGI_FORMAT_R8G8B8A8_UNORM ,DXGI_FORMAT_R16G16B16A16_FLOAT };

	return true;
}

bool fxcc::graph::directX11::RenderStates::InitSamplerDesc()
{
	auto device = Device();

	{
		D3D11_SAMPLER_DESC samplerDesc = {};
		samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; 
		samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; 
		samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; 
		samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; 
		samplerDesc.MipLODBias = 0.0f;
		samplerDesc.MaxAnisotropy = 1; 
		samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; 
		samplerDesc.BorderColor[0] = 1.0f; 
		samplerDesc.BorderColor[1] = 1.0f; 
		samplerDesc.BorderColor[2] = 1.0f; 
		samplerDesc.BorderColor[3] = 1.0f; 
		samplerDesc.MinLOD = 0; 
		samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

		{
			auto& samplerTypeDesc = m_SamplerDescs[(int)SamplerType::_sampler_2d_default_];
			samplerTypeDesc.m_Name = "texture 2d default";
			HRESULT hr = device->CreateSamplerState(&samplerDesc, samplerTypeDesc.m_SamplerState.GetAddressOf());
			if (FAILED(hr)) {
				ztclog::info("failed init sampler State");
				return false;
			}
		}
		{
			auto& samplerTypeDesc = m_SamplerDescs[(int)SamplerType::_sampler_2d_array_default];
			samplerTypeDesc.m_Name = "texture 2d array default";
			HRESULT hr = device->CreateSamplerState(&samplerDesc, samplerTypeDesc.m_SamplerState.GetAddressOf());
			if (FAILED(hr)) {
				ztclog::info("failed init sampler State");
				return false;
			}
		}
		{
			auto& samplerTypeDesc = m_SamplerDescs[(int)SamplerType::_sampler_cube_default_];
			samplerTypeDesc.m_Name = "texture cube default";
			HRESULT hr = device->CreateSamplerState(&samplerDesc, samplerTypeDesc.m_SamplerState.GetAddressOf());
			if (FAILED(hr)) {
				ztclog::info("failed init sampler State");
				return false;
			}
		}
	}
	return true;

}

void fxcc::graph::directX11::RenderStates::SetSamplerState(const int startSlot, const int numSlot, const fxcc::graph::common::SamplerType& samplerType)
{
	auto context = Context();
	const auto& samplerTypeDesc = m_SamplerDescs[(int)samplerType];
	const auto& samplerState = samplerTypeDesc.m_SamplerState;

	context->PSSetSamplers(startSlot, numSlot, samplerState.GetAddressOf());

};

void fxcc::graph::directX11::RenderStates::SetSamplerStates()
{
	SetSamplerState(0, 1, fxcc::graph::common::SamplerType::_sampler_2d_array_default);

	SetSamplerState(1, 1, fxcc::graph::common::SamplerType::_sampler_2d_default_);

	SetSamplerState(2, 1, fxcc::graph::common::SamplerType::_sampler_cube_default_);

}

const fxcc::graph::directX11::FormatDesc fxcc::graph::directX11::RenderStates::GetFormatDesc(const int channel)
{
	return m_FormatDescs[channel];
}

const DXGI_FORMAT fxcc::graph::directX11::RenderStates::GetFormat(const int numChannel, bool hdr)
{
	m_FormatDescs;
	const auto& formatDesc = GetFormatDesc(numChannel);
	return hdr ? formatDesc.m_hdrFormat: formatDesc.m_Format;
}
;

bool fxcc::graph::directX11::RenderStates::InitModeDesc()
{
	m_ModeDescs[(int)common::ModeType::_mode_Triangles_] = { "Triangles", D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST };
	//m_ModeDescs[(int)common::ModeType::_mode_Triangle_fan_] = { "triangle Fan",D3D11_PRIMITIVE_TOPOLOGY_TRIANGLEFAN };
	m_ModeDescs[(int)common::ModeType::_mode_Triangle_stripe_] = { "triangle stripe ",D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP };
	m_ModeDescs[(int)common::ModeType::_mode_Lines_] = { "Lines", D3D11_PRIMITIVE_TOPOLOGY_LINELIST };
	m_ModeDescs[(int)common::ModeType::_mode_Line_Stripe] = { "Line Stripe", D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP };
	//m_ModeDescs[(int)common::ModeType::_mode_Line_Loop] = { "Line Loop" , D3D11_PRIMITIVE_TOPOLOGY_LINELOOP };
	m_ModeDescs[(int)common::ModeType::_mode_points_] = { "Points", D3D11_PRIMITIVE_TOPOLOGY_POINTLIST };

	return true;
};

bool fxcc::graph::directX11::RenderStates::InitIndexDesc()
{
	m_IndexDescs[(int)common::IndexType::_index_unsigned_byte_] = { "unsigned byte", sizeof(unsigned char),DXGI_FORMAT_R8_UINT};
	m_IndexDescs[(int)common::IndexType::_index_unsigned_short_] = { "unsigned short",sizeof(unsigned short), DXGI_FORMAT_R16_UINT};
	m_IndexDescs[(int)common::IndexType::_index_unsigned_int_] = { "unsigned int",sizeof(unsigned int),  DXGI_FORMAT_R32_UINT };

	return true;
};

bool fxcc::graph::directX11::RenderStates::InitVertexDesc()
{
	m_VertexDescs[(int)common::VertexType::_vertex_fixed_] = { "Fixed Vertex" , sizeof(fxcc::graph::common::VertexFixed) };
	m_VertexDescs[(int)common::VertexType::_vertex_fixed_].m_InputLayouts = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    2, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 3, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "BIGTANGENT",0, DXGI_FORMAT_R32G32B32_FLOAT,4, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	m_VertexDescs[(int)common::VertexType::_vertex_skinned_] = { "Skinned Vertex" , sizeof(::common::VertexSkinned) };
	m_VertexDescs[(int)common::VertexType::_vertex_skinned_].m_InputLayouts =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL",   0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TANGENT",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0,0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "BIGTANGENT",0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "BONES1",   0, DXGI_FORMAT_R32G32B32A32_SINT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "WEIGHTS1", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "BONES2",   0, DXGI_FORMAT_R32G32B32A32_SINT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "WEIGHTS2", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
	};

	return true;
};

VertexTypeDesc fxcc::graph::directX11::RenderStates::GetVertexDesc(const common::VertexType& type)
{
	return m_VertexDescs[int(type)];
}


IndexTypeDesc fxcc::graph::directX11::RenderStates::GetIndexDesc(const common::IndexType type)
{
	return m_IndexDescs[(int)type];
}

ModeTypeDesc fxcc::graph::directX11::RenderStates::GetModeTypeDesc(const common::ModeType& type)
{
	return m_ModeDescs[(int)type];
};

ID3D11Device* fxcc::graph::directX11::RenderStates::Device()
{
	return m_Device;
}

ID3D11DeviceContext* fxcc::graph::directX11::RenderStates::Context()
{
	return m_Context;
}

fxcc::graph::directX11::RenderStates& fxcc::graph::directX11::RenderStates::Inst()
{
	static fxcc::graph::directX11::RenderStates res;
	return res;
}